/**
 ***********************************************************************************************************************
 * Copyright (c) 2021, XIE LI Co.,Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 *
 * @file        udp_server.c
 *
 * @brief       udp_server functions.
 *
 * @revision
 * Date         Author          Notes
 * 2021-09-30   Xie Li      First Version
 ***********************************************************************************************************************
 */
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <unistd.h>

#define HOST_PORT_NUM   50000

/**
 ***********************************************************************************************************************
 * @brief           udp_server_run
 *
 * @param[in]       none
 *
 * @return          none
 ***********************************************************************************************************************
 */
int udp_server_run(void)
{
    struct sockaddr_in srv_addr, cli_addr;
    int sock_fd;
    char add_str[INET_ADDRSTRLEN];
    char buf[64];
    char *message = "hello client";

    sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock_fd == -1) {
        printf("Socket create failed\r\n");
        return -1;
    }

    memset(&srv_addr, 0, sizeof(srv_addr));
    srv_addr.sin_family = AF_INET;
    srv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    srv_addr.sin_port = htons(HOST_PORT_NUM);

    if (bind(sock_fd, (struct sockaddr *)&srv_addr, sizeof(struct sockaddr_in)) == -1) {
        printf("Socket bind failed, errno=%d\r\n", errno);
        goto exit;
    }

    socklen_t socklen = sizeof(struct sockaddr_in);
    while (1) {
        int len = recvfrom(sock_fd, buf, sizeof(buf), 0, (struct sockaddr *)&cli_addr, &socklen);
        if (len == -1) {
            printf("Receive from client failed, errno=%d\r\n", errno);
            goto exit;
        }
        
        inet_ntop(AF_INET, &cli_addr.sin_addr, add_str, INET_ADDRSTRLEN);
        printf("Received %d bytes from client (%s:%d):\r\n", len, add_str, ntohs(cli_addr.sin_port));
        printf("%.*s\r\n", len, buf);

        /* echo */
        if (sendto(sock_fd, message, strlen(message), 0, (struct sockaddr *)&cli_addr, sizeof(struct sockaddr_in)) == -1) {
            printf("Send to client failed, errno=%d\r\n", errno);
            goto exit;
        }
    }

    return 0;

exit:
    shutdown(sock_fd, SHUT_RDWR);
    // close(sock_fd);
    return -1;
}